<!DOCTYPE html>
<title>IndexedDB: Verify transaction activation behavior around microtasks</title>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="resources/testharness-helpers.js"></script>
<script>

function isTransactionActive(tx, storeName) {
    try {
        tx.objectStore(storeName).get(0);
        return true;
    } catch (ex) {
        // The exception could be TransactionInactiveError or InvalidStateError
        // depending on the test and whether the transaction has committed yet.
        return false;
    }
}

indexeddb_test(
    function(t, db) {
        db.createObjectStore('store');
    },
    function(t, db) {
        Promise.resolve().then(t.step_func(function() {
            var tx = db.transaction('store');
            var request = tx.objectStore('store').get(0);
            request.onerror = t.unreached_func('request should not fail');
            request.onsuccess = t.step_func(function() {
                assert_true(isTransactionActive(tx, 'store'),
                            'Transaction should be active during event dispatch');
                setTimeout(t.step_func(function() {
                    assert_false(isTransactionActive(tx, 'store'),
                                 'Transaction should be inactive once control returns to event loop');
                    t.done();
                }), 0);
            });
        }));
    },
    'Transactions created in microtasks are deactivated when control returns to the event loop'
);

indexeddb_test(
    function(t, db) {
        db.createObjectStore('store');
    },
    function(t, db) {
        var aesAlgorithmKeyGen = {name: "AES-CBC", length: 128};
        crypto.subtle.generateKey(aesAlgorithmKeyGen, false, ["encrypt"]).then(t.step_func(function() {
            var tx = db.transaction('store');
            var request = tx.objectStore('store').get(0);
            request.onerror = t.unreached_func('request should not fail');
            request.onsuccess = t.step_func(function() {
                assert_true(isTransactionActive(tx, 'store'),
                            'Transaction should be active during event dispatch');
                setTimeout(t.step_func(function() {
                    assert_false(isTransactionActive(tx, 'store'),
                                 'Transaction should be inactive once control returns to event loop');
                    t.done();
                }), 0);
            });
        }));
    },
    'Transactions created in microtasks resolved by host behavior are deactivated when control returns to the event loop'
);

indexeddb_test(
    function(t, db) {
        db.createObjectStore('store');
    },
    function(t, db) {
        var tx;
        Promise.resolve().then(function() {
            tx = db.transaction('store');
            assert_true(isTransactionActive(tx, 'store'),
                        'Transaction should be active when created');
        }).then(t.step_func(function() {
            assert_true(isTransactionActive(tx, 'store'),
                        'Transaction should be active until control returns to event loop');
            setTimeout(t.step_func(function() {
                assert_false(isTransactionActive(tx, 'store'),
                            'Transaction should be inactive once control returns to event loop');
                t.done();
            }), 0);
        }));
    },
    'Transactions created in microtasks remain active in subsequent microtasks'
);

indexeddb_test(
    function(t, db) {
        db.createObjectStore('store');
    },
    function(t, db) {
        var tx = db.transaction('store');
        var request = tx.objectStore('store').get(0);
        request.onerror = t.unreached_func('request should not fail');
        request.onsuccess = t.step_func(function() {
            assert_true(isTransactionActive(tx, 'store'),
                        'Transaction should be active during event dispatch');
            Promise.resolve().then(t.step_func(function() {
                assert_true(isTransactionActive(tx, 'store'),
                            'Microtasks are run as part of event dispatch, so transaction should still be active');
                setTimeout(t.step_func(function() {
                    assert_false(isTransactionActive(tx, 'store'),
                                'Transaction should be inactive once control returns to the event loop');
                    t.done();
                }), 0);
            }));
        });
    },
    'Within request event dispatch, transactions remain active across microtasks'
);

</script>
